﻿using System;
using System.Activities;

namespace NMemcached.Client.Activities
{
    /// <summary>
    /// Stores an item the cache
    /// </summary>
    public sealed class StorageActivity : KeyedMemecachedActivity
    {
        /// <summary>
        /// Gets or sets the storage action
        /// </summary>
        public InArgument<StorageAction> StoreAction { get; set; }

        /// <summary>
        /// Gets or sets the data to be stored
        /// </summary>
        public InArgument<object> Data { get; set; }

        /// <summary>
        /// Gets or sets the expiration timestamp of the item stored
        /// </summary>
        public InArgument<DateTime?> Expiration { get; set; }

        /// <summary>
        /// Gets or sets the check and set unique value
        /// </summary>
        public InArgument<ulong?> CasUnique { get; set; }

        /// <summary>
        /// Gets or sets the response code from the storage operation
        /// </summary>
        public OutArgument<ResponseCode> Response { get; set; }

        /// <summary>
        /// Initializes a new instance of the StorageActivity class
        /// </summary>
        public StorageActivity()
            : base()
        {
        }

        /// <summary>
        /// Performs the execution of the activity
        /// </summary>
        /// <param name="context">The execution context under which the activity executes</param>
        protected override void Execute(CodeActivityContext context)
        {
            base.Execute(context);

            StorageAction action = this.StoreAction.Get(context);
            object data = this.Data.Get(context);
            DateTime expires = this.Expiration.Get(context) ?? DateTime.MinValue;
            ulong? casUnique = this.CasUnique.Get(context);

            ResponseCode response = ResponseCode.NoError;

            if (String.IsNullOrWhiteSpace(this.CacheKey))
            {
                throw new ArgumentNullException("Key");
            }
            else
            {
                switch (action)
                {
                    case StorageAction.Add:
                        response = this.CacheConnection.Add(this.CacheKey, data, expires);
                        break;
                    case StorageAction.Append:
                        response = this.CacheConnection.Append(this.CacheKey, data);
                        break;
                    case StorageAction.CheckAndSet:
                        if (casUnique.HasValue)
                        {
                            response = this.CacheConnection.CheckAndSet(this.CacheKey, data, expires, (ulong)casUnique);
                        }
                        else
                        {
                            throw new ArgumentNullException("CasUnique");
                        }
                        break;
                    case StorageAction.Prepend:
                        response = this.CacheConnection.Prepend(this.CacheKey, data);
                        break;
                    case StorageAction.Replace:
                        response = this.CacheConnection.Replace(this.CacheKey, data, expires);
                        break;
                    case StorageAction.Set:
                        response = this.CacheConnection.Set(this.CacheKey, data, expires);
                        break;
                }

                this.Response.Set(context, response);
            }
        }
    }
}